#include <iostream>
#include "interface.h"

sdl::Window::Wrapped window_;
gl::Context context_ = nullptr;
std::vector<std::shared_ptr<IDrawable>> draws_;
std::vector<std::function<std::shared_ptr<IDrawable>()>> createDraws_;
int draw_index_ = 0;
const char *title_ = "OpenGL3.3";

void adjustDrawIndex() {
  if (draw_index_ < 0) draw_index_ = 0;
  if (draw_index_ >= draws_.size()) draw_index_ = draws_.size() - 1;
}
std::shared_ptr<IDrawable> currentDrawable() {
  adjustDrawIndex();
  return draws_.at(draw_index_);
}
void changeTitle() {
  auto d = currentDrawable();
  if (!d) return;
  std::string title = title_;
  title += " - ";
  title += d->title();
  window_->setTitle(title.c_str());
}
void handleEvent(sdl::event::Event &evt) {
  if (evt.key.keysym.sym == SDLK_RIGHT) {
    ++draw_index_;
    adjustDrawIndex();
    changeTitle();
    return;
  } else if (evt.key.keysym.sym == SDLK_LEFT) {
    --draw_index_;
    adjustDrawIndex();
    changeTitle();
    return;
  }

  auto d = currentDrawable();
  if (!d) return;
  d->processInput(evt);
}
void update(float elapsedTime) {
  auto d = currentDrawable();
  if (d) d->update(elapsedTime);
}
void render() {
  glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  auto d = currentDrawable();
  if (d) d->render();
  gl::swapWindow(window_);
}

void addCreateDrawable(std::function<std::shared_ptr<IDrawable>()> fun) {
  if (!fun) return;
  createDraws_.emplace_back(fun);
}
void createDrawable() {
  for (auto &v : createDraws_) {
    if (!v) continue;
    auto d = v();
    if (!d) continue;
    draws_.emplace_back(d);
  }
}

int main(int argc, char *argv[]) {
  gl::setAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
  gl::setAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
  gl::setAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

  auto rst = sdl::init(SDL_INIT_EVERYTHING);
  if (sdl::isFailed(rst)) {
    std::cout << "error init." << std::endl;
    return -1;
  }

  window_ = sdl::Window::create(title_, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED
      , 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
  if (window_) {
    context_ = gl::createContext(window_);
    gl::makeCurrent(window_, context_);
  }

  if (!context_) {
    if (window_) window_->destroy();
    sdl::quit();
    std::cout << "error create window or opengl context." << std::endl;
    return 0;
  }

  createDrawable();

  for (auto &v : draws_)
    v->init();

  changeTitle();

  bool quit = false;
  sdl::event::Event evt;
  Uint32 lastTime = 0, curTime = 0;
  float elapsedTime = 0.f;
  while (!quit) {
    while (sdl::event::poll(&evt)) {
      if (evt.type == SDL_QUIT) {
        quit = true;
      }
      handleEvent(evt);
    }
    curTime = sdl::timer::getTicks();
    elapsedTime = (curTime - lastTime) / 1000.f;
    lastTime = curTime;
    update(elapsedTime);
    render();
  }

  for (auto &v : draws_)
    v->uninit();

  gl::deleteContext(context_);
  window_->destroy();

  sdl::quit();
  return 0;
}
